package com.bosssoft.user.permission.center.serve.service.impl;


import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNodeConfig;
import cn.hutool.core.lang.tree.TreeUtil;
import com.bosssoft.user.permission.center.serve.dao.entity.Role;
import com.bosssoft.user.permission.center.serve.dao.entity.RoleCompany;
import com.bosssoft.user.permission.center.serve.dao.entity.RoleResource;
import com.bosssoft.user.permission.center.serve.dao.entity.RoleUser;
import com.bosssoft.user.permission.center.serve.dao.mapper.RoleCompanyMapper;
import com.bosssoft.user.permission.center.serve.dao.mapper.RoleMapper;
import com.bosssoft.user.permission.center.serve.dao.mapper.RoleResourceMapper;
import com.bosssoft.user.permission.center.serve.dao.mapper.RoleUserMapper;
import com.bosssoft.user.permission.center.serve.pojo.dto.*;
import com.bosssoft.user.permission.center.serve.pojo.query.RoleQuery;
import com.bosssoft.user.permission.center.serve.pojo.query.RoleUserQuery;
import com.bosssoft.user.permission.center.serve.pojo.vo.RoleCompanyVO;
import com.bosssoft.user.permission.center.serve.pojo.vo.RoleUserVO;
import com.bosssoft.user.permission.center.serve.pojo.vo.RoleVO;
import com.bosssoft.user.permission.center.serve.pojo.vo.TreeNode;
import com.bosssoft.user.permission.center.serve.service.RoleService;

import com.bosssoft.user.permission.center.serve.util.LoginTokenUtil;
import com.bosssoft.user.permission.center.serve.util.SingleAutoFill;
import com.github.pagehelper.PageHelper;
import common.annotation.ApiLog;
import common.core.JwtPayloadHolder;
import common.data.commonresponse.CommonPage;
import common.util.IdGeneratorUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;


@Service
public class RoleServiceImpl implements RoleService {

    /**
     * 描述: id生成器
     * 作者: lljm
     * 日期: 2024/6/12
     */

    @Autowired
    private  IdGeneratorUtil idGeneratorUtil;

    /**
     * 描述: 角色mapper
     * 作者: lljm
     * 日期: 2024/6/12
     */

    @Autowired
    private RoleMapper roleMapper;

    /**
     * 描述:
     * 作者: lljm
     * 日期: 2024/6/12
     */

    @Autowired
    private RoleResourceMapper roleResourceMapper;

    @Autowired
    private RoleCompanyMapper roleCompanyMapper;
    
    @Autowired
    private RoleUserMapper roleUserMapper;


    /**
     * 描述: 用于单个对象的公共属性的填充
     * 作者: lljm
     * 日期: 2024/6/13
     */

    @Autowired
    private SingleAutoFill singleAutoFill;

    /* ------------------------------角色相关------------------------------*/


    @ApiLog
    @Override
    public CommonPage<RoleVO> search(RoleQuery roleQuery) {
        List<Long> ls = new ArrayList<>();
        ls.add(LoginTokenUtil.parseTokenToLoginDTO().getCompanyId());
        roleQuery.setCompanyIds(ls);
        PageHelper.startPage(roleQuery.getPageIndex(), roleQuery.getPageSize());
        List<Long> companyList = roleQuery.getCompanyIds();
        String name = roleQuery.getName();
        List<RoleVO> roleList = roleMapper.searchRoleList(companyList,name);
        return CommonPage.restPage(roleList);

    }

    @ApiLog
    @Override
    @Transactional
    public Boolean add(RoleDTO roleDTO) {
        roleDTO.setCompanyId(LoginTokenUtil.parseTokenToLoginDTO().getCompanyId());
        roleDTO.setOrgId(LoginTokenUtil.parseTokenToLoginDTO().getOrgId());
        roleDTO.setTenantId(roleDTO.getTenantId());
        Role role = new Role();
        BeanUtils.copyProperties(roleDTO,role);
        if(role.getId()==null){
            role.setId(idGeneratorUtil.snowflakeId());
        }
        return roleMapper.insert(role) ;
    }

    @ApiLog
    @Override
    @Transactional
    public Boolean update(RoleDTO roleDTO) {
        Role role = new Role();
        BeanUtils.copyProperties(roleDTO,role);
        return roleMapper.update(role) ;
    }

    @ApiLog
    @Override
    @Transactional
    public Boolean remove(List<Long> ids) {
        roleUserMapper.batchDeleteRolesWithUser(ids);
        roleResourceMapper.batchDeleteRolesWithResource(ids);
        roleCompanyMapper.batchDeleteRolesWithCompany(ids);
        return roleMapper.batchDeleteRoles(ids);
    }


    @ApiLog
    @Override
    public String checkRoleCode(String code, Long roleId) {
        //如果当前请求参数未携带roleId，则为新建角色时的查询，携带了，则为修改角色时的查询
        if(roleId == null){
            roleId = (long) -1;
        }

        if("".equals(code)||roleMapper.checkRoleCodeAndRoleId(code,roleId)>0){
            return "unusable";
        }
        return "usable";
    }



    /* ------------------------------角色  资源 相关------------------------------*/


    @ApiLog
    @Override
    @Transactional
    public Boolean allocateResource(RoleResourceDTO roleResourceDTO) {
        //替换当前参数中的公司id等信息，参数中的信息有误
        roleResourceDTO.setCompanyId(LoginTokenUtil.parseTokenToLoginDTO().getCompanyId());
        roleResourceDTO.setTenantId(LoginTokenUtil.parseTokenToLoginDTO().getTenantId());
        roleResourceDTO.setOrgId(LoginTokenUtil.parseTokenToLoginDTO().getOrgId());
        //用于存储每一条资源与角色的记录
        List<RoleResource> roleResourceList = new ArrayList<>();
        //确定资源的数量，用于下方雪花id的生成
        List<Long> resourceIds = roleResourceDTO.getResourceIds();
        int resourceCount = resourceIds.size();
        for (int i = 0; i < resourceCount; i++) {
            RoleResource roleResource = new RoleResource();
            BeanUtils.copyProperties(roleResourceDTO,roleResource);
            roleResource.setId(idGeneratorUtil.snowflakeId());
            roleResource.setResourceId(resourceIds.get(i));
            //使用注解的方式填充单个roleResource对象
            singleAutoFill.singleAutoFill(roleResource);
            //获得完整的RoleResource信息后加入到列表中，用于后续批量插入
            roleResourceList.add(roleResource);
        }
        //TODO 这里的RoleIds可能后续需要更改为RoleId，不能够进行批量角色的资源分配操作
        //插入前需要进行删除
       // roleResourceMapper.batchDeleteTheResourcesOfRole(roleResourceDTO.getRoleId());
        //批量插入
      //  return roleResourceMapper.batchAllocateResource(roleResourceList);
        return null;
    }



    /**
     * 描述: 获取单个角色资源树方法
     * 作者: lljm
     * 日期: 2024/6/13
     * @param roleResourceCheckDTO
     */
    @ApiLog
    @Override
    @Transactional
    public List<Tree<String>> showRoleResource(RoleResourceCheckDTO roleResourceCheckDTO) {

        List<Long> roleIds = roleResourceCheckDTO.getRoleIds();
        //从threadLocal中获取租户id
        Long tenantId = LoginTokenUtil.parseTokenToLoginDTO().getTenantId();
        List<TreeNode> list ;
        if(roleIds.size()==1) {
            //此时角色id只有一个，直接查询单个角色资源树，需要选中标识符
            Long roleId = roleIds.get(0);
            list = roleResourceMapper.showSingleRoleResource(roleId,tenantId);
        }else {
            //此时角色id有多个，直接查询资源数据树，不需要标识符，返回的结果中标识符需要被全部设置为0
            List<TreeNode> temp = roleResourceMapper.showMultipleRoleResource(roleIds,tenantId);
            temp.forEach(treeNode -> treeNode.setExistsFlag(0));
            list = temp;
        }

        List<TreeNode> list2 = CollUtil.newArrayList();
//浅拷贝赋值
        list2.addAll(list);
// rootId
        String pid = "-1";
//配置
        TreeNodeConfig nodeConfig = new TreeNodeConfig();
// 自定义属性名 都要默认值的
//设置ID对应的名称
        nodeConfig.setIdKey("id");
// 最大递归深度 3级目录
        nodeConfig.setDeep(3);
// 入参
// tree: 最终要返回的数据
// node: lists数据
// 返回
// Tree<String>
// Tree: 转换的实体 为数据源里的对象类型
// String: ID类型
//转换器
        List<Tree<String>> treeList = TreeUtil.build(list2, pid, nodeConfig,
                (node, tree) -> {
// 设置existsFlag 存在标识符号
                    tree.putExtra("existsFlag", node.getExistsFlag());
//id
                    tree.setId(String.valueOf(node.getId()));
//姓名
                    tree.setName(node.getName());
//获取父节点id
                    tree.setParentId(String.valueOf(node.getParentId()));
                });
        return treeList;
    }


    /**
     * 描述: 进行角色分配前，需要对角色是否拥有资源进行检查
     * 作者: lljm
     * 日期: 2024/6/13
     */


    @ApiLog
    @Override
    public String checkRoleIfHavingResource(Long roleId) {
        if(roleResourceMapper.checkRoleIfHavingResource(roleId)==0){
            return "请对角色分配资源后，再进行本次分配用户操作";
        }

        return "当前角色拥有资源，可以进行分配用户操作";
    }

    /* ------------------------------角色 资源  公司   相关------------------------------*/

    /*仅有一个功能： 为多角色 分配公司和资源  实现事物*/

    @ApiLog
    @Override
    @Transactional
    public Boolean allocateResourceAndCompany(RoleResourceAndCompanyDTO roleResourceAndCompanyDTO) {
        roleResourceAndCompanyDTO.setCompanyId(LoginTokenUtil.parseTokenToLoginDTO().getCompanyId());
        roleResourceAndCompanyDTO.setOrgId(LoginTokenUtil.parseTokenToLoginDTO().getOrgId());
        roleResourceAndCompanyDTO.setTenantId(LoginTokenUtil.parseTokenToLoginDTO().getTenantId());
        //获取角色与公司分配信息的列表
        List<RoleCompany> roleCompanyList = new ArrayList<>();
        for (Long roleId : roleResourceAndCompanyDTO.getRoleIds()) {
            for (Long authCompanyId : roleResourceAndCompanyDTO.getAuthCompanyIds()) {
                RoleCompany roleCompany = new RoleCompany();
                BeanUtils.copyProperties(roleResourceAndCompanyDTO, roleCompany);
                roleCompany.setId(idGeneratorUtil.snowflakeId());
                roleCompany.setRoleId(roleId);
                roleCompany.setAuthCompanyId(authCompanyId);
                //利用aop填充数据
                singleAutoFill.singleAutoFill(roleCompany);
                roleCompanyList.add(roleCompany);
            }
        }
        //获取角色与资源分配信息的列表
        List<RoleResource> roleResourceList = new ArrayList<>();
        for (Long roleId : roleResourceAndCompanyDTO.getRoleIds()) {
            for (Long resourceId : roleResourceAndCompanyDTO.getResourceIds()) {
                RoleResource roleResource = new RoleResource();
                BeanUtils.copyProperties(roleResourceAndCompanyDTO, roleResource);
                roleResource.setId(idGeneratorUtil.snowflakeId());
                roleResource.setRoleId(roleId);
                roleResource.setResourceId(resourceId);
                //利用aop填充数据
                singleAutoFill.singleAutoFill(roleResource);
                roleResourceList.add(roleResource);
            }
        }
        //插入前需要删除旧数据，根据角色ids删除 角色资源关系表 和 角色公司关系表 中的内容
        roleResourceMapper.batchDeleteRolesWithResource(roleResourceAndCompanyDTO.getRoleIds());
        roleCompanyMapper.batchDeleteRolesWithCompany(roleResourceAndCompanyDTO.getRoleIds());

        //进行数据插入

        // 当列表为空时，说明当前角色未绑定任何公司，不在数据库中做其他操作
        if (!roleCompanyList.isEmpty()) {
            roleCompanyMapper.batchAllocateCompany(roleCompanyList);
        }
        // 当列表为空时，说明当前角色未绑定任何资源，不在数据库中做其他操作
        if (!roleResourceList.isEmpty()) {
            roleResourceMapper.batchAllocateResource(roleResourceList);
        }

        return true;
    }




    /* ------------------------------角色  公司  相关------------------------------*/

    @ApiLog
    @Override
    @Transactional
    public Boolean allocateCompany(RoleCompanyDTO roleCompanyDTO) {
        roleCompanyDTO.setTenantId(LoginTokenUtil.parseTokenToLoginDTO().getTenantId());
        List<RoleCompany> roleCompanyList = new ArrayList<>();
        //为什么不直接在数据库做批量操作？ 因为需要雪花id
        for (Long authCompanyId : roleCompanyDTO.getAuthCompanyIds()) {
            RoleCompany roleCompany = new RoleCompany();
            BeanUtils.copyProperties(roleCompanyDTO,roleCompany);
            roleCompany.setId(idGeneratorUtil.snowflakeId());
            roleCompany.setAuthCompanyId(authCompanyId);
            //利用aop填充数据
            singleAutoFill.singleAutoFill(roleCompany);
            roleCompanyList.add(roleCompany);
        }
        //本次分配前需要删除之前对应角色与公司关系
//        roleCompanyMapper.batchDeleteTheCompanyOfRole(roleCompanyDTO.getRoleId());
//        //当列表为空时，说明当前角色未绑定任何公司，不在数据库中做其他操作，直接返回true
//        if (roleCompanyList == null || roleCompanyList.isEmpty()) {
//            return true;
//        }
//        return roleCompanyMapper.batchAllocateCompany(roleCompanyList);
        return null;
    }

    @ApiLog
    @Override
    @Transactional
    public List<RoleCompanyVO> checkRoleCompany(List<Long> roleIds) {


        if(roleIds.size()==1){
            //当列表数量为1时，说明当前的角色id只有一个，直接查询单个角色的公司信息，需要绑定标识
            return roleCompanyMapper.checkSingleRoleCompany(roleIds.get(0));
        }else {
            //当列表数量>1时，说明当前角色有多个，则直接查询公司信息，不需要绑定标识，设定为0
            List<RoleCompanyVO> temp= roleCompanyMapper.checkMultipleRoleCompany(roleIds);
            temp.forEach(roleCompanyVO -> roleCompanyVO.setBindStatus(0L));
            return temp;
        }
    }


    /* ------------------------------角色  用户  相关------------------------------*/

    /**
     * 描述:  查看角色与用户关系，返回格式是页
     * 作者: lljm
     * 日期: 2024/6/16
     */

    @ApiLog
    @Override
    public CommonPage<RoleUserVO> checkRoleUser(RoleUserQuery roleUserQuery) {
        //替换当前请求参数中的公司id信息，用threadlocal中的数据替换
        roleUserQuery.setCompanyId(LoginTokenUtil.parseTokenToLoginDTO().getCompanyId());

        PageHelper.startPage(roleUserQuery.getPageIndex(),roleUserQuery.getPageSize());
        Long roleId = roleUserQuery.getRoleId();
        String name = roleUserQuery.getName();
        Long companyId = roleUserQuery.getCompanyId();
        List<RoleUserVO> roleUserVOList = roleUserMapper.checkRoleUser(roleId,name,companyId);
        return CommonPage.restPage(roleUserVOList);
    }


    /**
     * 描述: 对于已经查找出来的一页进行分配操作
     * 作者: lljm
     * 日期: 2024/6/16
     */

    @ApiLog
    @Override
    @Transactional
    public Boolean allocateUser(RoleUserDTO roleUserDTO) {
        Long roleId = roleUserDTO.getRoleId();
        List<Long> currentPageUserIds = roleUserDTO.getCurrentPageUserIds();
        List<Long> currentPageSelectedUserIds = roleUserDTO.getCurrentPageSelectedIds();
        //先尝试删除当前页所有组合对的信息
        roleUserMapper.batchDeletePartRolesWithUser(roleId,currentPageUserIds);
        //然后插入当前页的新组合对
        List<RoleUser> roleUserList = new ArrayList<>();
        for (Long userId : currentPageSelectedUserIds) {
            RoleUser roleUser = new RoleUser();
            BeanUtils.copyProperties(roleUserDTO,roleUser);//拷贝角色id和租户id
            roleUser.setId(idGeneratorUtil.snowflakeId());
            roleUser.setUserId(userId);
            //利用aop填充数据
            singleAutoFill.singleAutoFill(roleUser);
            roleUserList.add(roleUser);
        }
        //检查本次分配用户数量是否是0，如果为0，则不进行数据库后续操作，直接返回成功
        if(roleUserList==null||roleUserList.size()==0){
            return true;
        }
        roleUserMapper.batchAllocateUser(roleUserList);
        return true;

    }


    


}
